/*
 * Toedo
 * Copyright (C) 2009-2010 J. Devauchelle and contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package org.toedo.gui.views;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TableColumn;
import org.toedo.controllers.Controller;
import org.toedo.controllers.DataController;
import org.toedo.controllers.events.EventConstants;
import org.toedo.controllers.events.EventController;
import org.toedo.gui.actions.DeleteNoteAction;
import org.toedo.gui.actions.OpenNoteAction;
import org.toedo.gui.dialogs.AttachmentsManagementDialog;
import org.toedo.gui.dialogs.TagsManagementDialog;
import org.toedo.gui.translations.Messages;
import org.toedo.model.BaseNote;
import org.toedo.model.Note;
import org.toedo.model.Tag;
import org.toedo.model.enums.SortDirection;
import org.toedo.preferences.PreferenceConstants;
import org.toedo.Activator;

public class NotesListView extends BaseNoteListViewPart implements PropertyChangeListener {

	public static final String ID = "toedo-core.NotesListView"; //$NON-NLS-1$
	
	private TableColumn mColumnTitle;
	
	private Image mNoteImage;
	
	class ViewContentProvider implements IStructuredContentProvider {
		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
            // do nothing
		}
		public void dispose() {
            // do nothing
		}

		public Object[] getElements(Object parent) {
			switch (mCurrentDisplayMode) {
			case EnAll : return DataController.getInstance().getProject().getNotesList().toArray();
			case EnUnTagged : return DataController.getInstance().getProject().getUntaggedNotesList().toArray();
			case EnFiltered : return DataController.getInstance().getProject().getFilteredNotesListByTag(mCurrentSelectedTagList).toArray();
			default : return DataController.getInstance().getProject().getTasksList().toArray();
			}
		}
	}

	class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
		
		public Image getColumnImage(Object obj, int index) {
			if (index == 0) {
				return mNoteImage;
			} else {
				return null;
			}
		}
		
		public String getColumnText(Object obj, int index) {
			String result;
			switch (index) {			
			case 1 : result = ((Note) obj).getTitle(); break;
			default : result = ""; //$NON-NLS-1$
			}
			return result;		
		}
	}
	
	public NotesListView() {
		super();
		
		Activator.getDefault();
		mNoteImage = Activator.getImageDescriptor("/icons/note-16.png").createImage(); //$NON-NLS-1$
	}
	
	@Override
	protected String getAllTableItemText() {
		return String.format("%s (%s)", Messages.TaskListView_AllTagsLabel, DataController.getInstance().getProject().getNotesList().size()); //$NON-NLS-1$;
	}

	@Override
	protected int getBaseNoteCountByTag(Tag tag) {
		return tag.getNotes().size();
	}

	@Override
	protected String getUnTaggedTableItemText() {
		return String.format("%s (%s)", Messages.TaskListView_UntaggedLabel, DataController.getInstance().getProject().getUntaggedNotesList().size()); //$NON-NLS-1$
	}
	
	@Override
	protected void setTagsSortDirection(SortDirection value) {
		Controller.getInstance().getPreferenceStore().setValue(PreferenceConstants.NOTESLIST_TAGS_SORT_DIRECTION, value.getValue());
	}
	
	@Override
	protected SortDirection getTagsSortDirection() {
		return SortDirection.getValueOf(Controller.getInstance().getPreferenceStore().getString(PreferenceConstants.NOTESLIST_TAGS_SORT_DIRECTION));
	}
	
	@Override
	protected void fireTagsSortEvent() {
		EventController.getInstance().fireGeneralEvent(EventConstants.EVT_NOTESLIST_TAGS_SORT_CHANGE, null, null);
	}
	
	@Override
	protected void openMenuHandler(SelectionEvent e) {
		ISelection selection = mViewer.getSelection();
		Object obj = ((IStructuredSelection)selection).getFirstElement();
		if (obj != null) {
			new OpenNoteAction((Note) obj).run();
		}
	}
	
	@Override
	protected void manageTagsMenuHandler(SelectionEvent e) {
		ISelection selection = mViewer.getSelection();
		Object obj = ((IStructuredSelection)selection).getFirstElement();
		if (obj != null) {
			new TagsManagementDialog(mParent.getShell(), (BaseNote) obj).open();
		}
	}
	
	@Override
	protected void manageAttachmentsMenuHandler(SelectionEvent e) {
		ISelection selection = mViewer.getSelection();
		Object obj = ((IStructuredSelection)selection).getFirstElement();
		if (obj != null) {
			new AttachmentsManagementDialog(mParent.getShell(), (Note) obj).open();
		}
	}
	
	@Override
	protected void deleteMenuHandler(SelectionEvent e) {
		ISelection selection = mViewer.getSelection();
		Object obj = ((IStructuredSelection)selection).getFirstElement();
		if (obj != null) {
			new DeleteNoteAction(mParent.getShell(), (Note) obj).run();
		}
	}
	
	@Override
	public void createPartControl(Composite parent) {
		super.createPartControl(parent);
		
		setPartName(Messages.NotesListView_NotesTitle);
		
		TableLayout layout = new TableLayout();
		layout.addColumnData(new ColumnWeightData(5, 5, true));
		layout.addColumnData(new ColumnWeightData(100, 150, true));
		
		mViewer.getTable().setLayout(layout);
		mViewer.getTable().setHeaderVisible(true);
				
		TableColumn columnIcon = new TableColumn(mViewer.getTable(), SWT.NONE);
		columnIcon.setText("");	//$NON-NLS-1$
		
		mColumnTitle = new TableColumn(mViewer.getTable(), SWT.NONE);
		mColumnTitle.setText(Messages.TaskListView_TitleColumn);
		mColumnTitle.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				changeSortDirection();
			}
		});
		
		mViewer.setContentProvider(new ViewContentProvider());
		mViewer.setLabelProvider(new ViewLabelProvider());
		mViewer.setInput(getViewSite());
		
		mViewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				ISelection selection = mViewer.getSelection();
				Object obj = ((IStructuredSelection)selection).getFirstElement();
				if (obj != null) {
					new OpenNoteAction((Note) obj).run();
				}
			}
		});
		
		mForm.setWeights(new int[] {30, 70});
		fillTagsList();
		buildMenus();
		
		EventController.getInstance().addGeneralEventsListener(this);
	}

	private void changeSortDirection() {
		SortDirection newDirection = SortDirection.EnAscending;
		SortDirection currentDirection = SortDirection.getValueOf(Controller.getInstance().getPreferenceStore().getString(PreferenceConstants.NOTESLIST_SORT_DIRECTION));
		
		switch (currentDirection) {
		case EnAscending : newDirection = SortDirection.EnDescending; break;
		case EnDescending : newDirection = SortDirection.EnAscending; break;
		}
		
		Controller.getInstance().getPreferenceStore().setValue(PreferenceConstants.NOTESLIST_SORT_DIRECTION, newDirection.getValue());
		
		EventController.getInstance().fireGeneralEvent(EventConstants.EVT_NOTESLIST_SORT_CHANGE, null, null);
	}

	private void refreshViewer(boolean initializeSelection) {
		switch (SortDirection.getValueOf(Controller.getInstance().getPreferenceStore().getString(PreferenceConstants.NOTESLIST_SORT_DIRECTION))) {
		case EnAscending : mColumnTitle.setImage(mSortUpImage); break;
		case EnDescending : mColumnTitle.setImage(mSortDownImage); break;
		default : mColumnTitle.setImage(null);
		}
		
		if (initializeSelection) {
			mCurrentDisplayMode = DisplayMode.EnAll;
			mTagsList.setSelection(-1);
			mFixedTagsList.setSelection(mAllTableItem);
		}
		
		mViewer.refresh();
	}
	
	private void refreshAll(boolean initializeSelection) {
		fillTagsList();
		
		refreshViewer(initializeSelection);
	}
	
	@Override
	public void propertyChange(PropertyChangeEvent arg0) {
		
		class TagsRefresher implements Runnable {
			public void run() {
				fillTagsList();
			}
		}
		
		class ViewerRefresher implements Runnable {
			
			private boolean mInitializeSelection;
			
			public ViewerRefresher(boolean initializeSelection) {
				mInitializeSelection = initializeSelection;
			}
			
			public void run() {
				refreshViewer(mInitializeSelection);
			}
		}
		
		class FullRefresher implements Runnable {
			
			private boolean mInitializeSelection;
			
			public FullRefresher(boolean initializeSelection) {
				mInitializeSelection = initializeSelection;
			}
			
			public void run() {
				refreshAll(mInitializeSelection);
			}
		}
		
		if (arg0.getPropertyName().equals(EventConstants.EVT_OPEN)) {
			
			Display.getDefault().asyncExec(new FullRefresher(true));
			
		} else if ((arg0.getPropertyName().equals(EventConstants.EVT_NEW_TAG)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_DELETE_TAG)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_PROJECT_PROPERTIES_CHANGE)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_ADD_NOTE)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_DELETE_NOTE)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_RENAME_BASENOTE)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_BASENOTE_TAG_CHANGE)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_MODIFY_NOTE))) {
			
			Display.getDefault().asyncExec(new FullRefresher(false));
			
		} else if (arg0.getPropertyName().equals(EventConstants.EVT_NOTESLIST_SORT_CHANGE)) {
			
			Display.getDefault().asyncExec(new ViewerRefresher(false));
			
		} else if (arg0.getPropertyName().equals(EventConstants.EVT_NOTESLIST_TAGS_SORT_CHANGE)) {
			
			Display.getDefault().asyncExec(new TagsRefresher());
			
		}
		
	}
	
	@Override
	public void setFocus() {
		// TODO Auto-generated method stub
		
	}
	
	public void dispose() {
		EventController.getInstance().removeGeneralEventsListener(this);
		
		mNoteImage.dispose();
		
		super.dispose();
	}

}
